package com.weizhu.swufer.core.cluster;

import com.weizhu.swufer.constant.SwuferConstant;
import com.weizhu.swufer.core.entity.InvokeParam;
import com.weizhu.swufer.core.exception.RpcBizException;
import com.weizhu.swufer.core.loadbalance.LoadBalancer;
import com.weizhu.swufer.core.exception.RpcException;
import com.weizhu.swufer.core.rpc.RpcRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class FailoverClusterInvoker extends AbstractClusterInvoker {

    private static final Logger logger = LoggerFactory.getLogger(FailoverClusterInvoker.class);

    @Override
    public Object doInvoke(InvokeParam invokeParam, String address) {
        RpcRequest rpcRequest = invokeParam.getRpcRequest();
        int tryTimes = getTryTimes(invokeParam);
        RuntimeException th = null;
        for (int i = 0; i < tryTimes; i++) {
            if (i > 0){
                address = loadBalancer.select(invokeParam);
            }
            try {
                return invokeGrpc(invokeParam,address);
            }catch (RpcException e){
                th = e;
                logger.error("invoke {} :{} for {} time has failed,remote address {}",rpcRequest.getInterfaceName(),
                        rpcRequest.getMethodName(),i,address,e);
            }catch (RpcBizException bizException){
                th = bizException;
                if (bizException.getBizRetry() == 0){
                    break;
                }
            }
        }
        throw th;
    }

    private int getTryTimes(InvokeParam invokeParam) {

        int tryTimes = invokeParam.getTryTimes();
        if (tryTimes <= 0){
            tryTimes = SwuferConstant.DEFAULT_TRY_TIMES;
        }
        return tryTimes;
    }


}
